/**
 * @file .
 * @author wangxiaowei0303@163.com
 */

#ifndef org_wxw0303_bishe_src_Filter_Filter_h_
#define org_wxw0303_bishe_src_Filter_Filter_h_

#include "../NoiseAlgorithm/NoiseAlgorithm.h"

/*
 * 空间滤波实现框架.考虑到空间滤波器的特性,即空间滤波器由邻域,以及邻域之上的操
 * 作组成.那么我们在实现一种空间滤波器时,只需要实现滤波之上的操作即可.
 * Filter 类会处理以下琐碎的问题:
 *   1. 进行空间相关时,图像边界的处理;当前默认使用 BORDER_REPICATE 填充.
 *   2. 遍历图像,提取邻域.
 *   3. 将处理结果赋值到图像指定坐标.
 * 同时,还会处理与邻域大小 row,col 相关的问题,如下:
 *   1. help();只会输出 row,col 的说明.
 *   2. set(),get();也只惠处理 row,col 参数.
 *   3. getSupportedArgs(); 也只会返回 row,col;
 * 实现一个新的空间滤波器;只需要继承 Filter,然后:
 *   1. 若对图像边界填充有特殊要求,实现 makeBorder() 函数.不过,一般情况下使用
 *      Filter 自带的即可.
 *   2. 实现 operOnNeigh(),即定义邻域之上的操作.
 */

class Filter: public NoiseAlgorithm {
public:
    inline 
    Filter();

    virtual
    ~Filter();

    virtual void
    help(std::string &buf) const;

    virtual void
    set(const char *argname,const char *argval);

    virtual const char*
    get(const char *argname,std::string &buf) const;
    
    virtual void
    getSupportedArgs(std::vector<std::string> &arglist) const;

    /*
     * 该函数会首先检查 img 的合法性,当 img 合法时,会调用 doProcess() 进行处理.
     * 在该函数检查 img 的合法性,是因为 5.3.1 中的均值滤波器对图像格式具有一样
     * 的要求.
     */
    virtual void
    process(cv::Mat &img);

protected:
    /*
     * 处理不合法的参数值.表明在 func() 函数中,检测到参数 arg 的值 val 不合法.
     */
    static void
    handleInvalidArgVal(const char *func,const char *arg,const char *val);
    
    /* 测试 n 是否是奇数,若返回真,则表明 n 是奇数. */
    static inline bool
    isOdd(unsigned long n); 
    
    /*
     * 在邻域之上进行的操作,也就是空间滤波器组成之一中的操作部分.
     * @param neighbor 函数内部不能修改 neighbor 的值,因为 neighbor 是对
     *                 原图像的部分引用,若修改,则会修改原图像.
     */
    virtual double
    operOnNeigh(const cv::Mat &neighbor) = 0;

    /*
     * 该函数首先根据需要计算出 t,b,l,r 的值(关于 t,b,l,r 的意义参考 
     * copyMakeBorder());然后创建一个行为 src.rows + t + b,列为 
     * src.cols + l + r 的新矩阵,然后将 src 复制到该新矩阵的中央,再
     * 按照一定的规则填充 t,b,l,r 边界的像素值.
     * 仅当滤波器对图像边界填充有特殊需要时,才应该实现该函数,该函数的
     * 默认实现 t == b == (row - 1) / 2;l == r == (col - 1) / 2;然后以
     * copyMakeBorder(BORDER_REPLICATE) 填充边界像素值.
     * @return 边界填充后的图像.
     */
    virtual cv::Mat
    makeBorder(const cv::Mat &src,int &t,int &b,int &l,int &r);
protected:
    int row;
    int col;
};


inline
Filter::Filter()
{
    this->row = 3;
    this->col = 3;
}

inline bool
Filter::isOdd(unsigned long n)
{
    return (n & 0x01) != 0;
}


#endif /* org_wxw0303_bishe_src_Filter_Filter_h_ */

